﻿Imports System.Reflection

Public MustInherit Class BaseEntity

    Private _Schema As TableSchema = Nothing

    Public Property Schema As TableSchema
        Get
            Return _Schema
        End Get
        Friend Set(ByVal value As TableSchema)
            _Schema = value
        End Set
    End Property

    Public Function GetValue(ByVal fieldName As String) As Object
        Return Me.GetType.GetProperty(fieldName).GetValue(Me, Nothing)
    End Function

    Public Sub SetValue(ByVal fieldName As String, ByVal fieldValue As Object)

        Dim PropertyInfo As PropertyInfo = Me.GetType.GetProperty(fieldName)
        Dim ActualValue As Object = ConvertValue(fieldValue, PropertyInfo.PropertyType)
        PropertyInfo.SetValue(Me, ActualValue, Nothing)

    End Sub

    Public Sub PopulateFromDictionary(ByVal data As Dictionary(Of String, String))

        ' Loop through each of the items in the dictionary
        For Each Datum As KeyValuePair(Of String, String) In data

            ' Get the associated property
            Dim PropertyName As String = Datum.Key
            Dim PropertyInfo As PropertyInfo = Me.GetType().GetProperty(PropertyName)

            ' Does the property exist and have the proper attribute defined?
            If PropertyInfo Is Nothing Then Throw New Exception("Cannot map the field '" + Datum.Key + "' to a property in the entity.")
            Dim Attribute As FieldAttribute() = PropertyInfo.GetCustomAttributes(GetType(FieldAttribute), False)
            If Attribute Is Nothing OrElse Attribute.Length = 0 Then Throw New Exception("The property '" + PropertyName + "' in the entity class must be marked with a field attribute.")

            ' Set the value of the property
            Dim PropertyValue As Object = ConvertValue(Datum.Value, PropertyInfo.PropertyType)
            PropertyInfo.SetValue(Me, PropertyValue, Nothing)

        Next

    End Sub

    ' TODO: StartTransaction / FinishTransaction
    ' TODO: Allow multiple conditions on find/delete
    ' TODO: Allow update column based on key & condition
    ' TODO: Add utils.GetLookupRecord and utils.GetChildRecords
    ' TODO: Invoke BaseEntity.CalculateComputedFields
    ' TODO: Tabify entity form
    ' TODO: Allow definition of custom menus, hence accepting a "GenerationParameters" class instance
    ' TODO: Create view form as seperate form with edit button
    ' TODO: Create Data Schema Management Studio

    Public Function ToDictionary() As Dictionary(Of String, String)

        ' Iterate through each of the properties available, that have been marked with the field attribute
        Dim Result As New Dictionary(Of String, String)
        For Each PropertyInfo As PropertyInfo In Me.GetType.GetProperties
            Dim Attribute As FieldAttribute() = PropertyInfo.GetCustomAttributes(GetType(FieldAttribute), False)
            If Attribute IsNot Nothing AndAlso Attribute.Length = 1 Then

                ' Add the property value to the entity data
                Dim PropertyName As String = PropertyInfo.Name
                Dim PropertyValue As Object = PropertyInfo.GetValue(Me, Nothing)
                Result.Add(PropertyName, Convert.ChangeType(PropertyValue, GetType(String)))

            End If
        Next
        Return Result

    End Function

    ''' <summary>
    ''' Returns a <see cref="System.String" /> that represents this instance, and is used in various places
    ''' to display a summary of the entity - for example, lookups display entity details using this method.
    ''' </summary>
    ''' <returns>
    ''' A <see cref="System.String" /> that represents this instance.
    ''' </returns>
    Public Overrides Function ToString() As String

        ' This default implementation goes through each marked property
        Dim Result As String = String.Empty
        For Each Field As PropertyInfo In GetEntityFields(Me.GetType)

            ' Add to the resulting string
            Dim Datum As String = Convert.ToString(Field.GetValue(Me, Nothing))
            If Datum <> "" Then
                If Result <> "" Then Result += " "
                Result += Datum
            End If

        Next

        ' Return the string
        Return Result

    End Function

    ''' <summary>
    ''' Validates the values contained in the entity, returning errors and warnings.
    ''' </summary>
    ''' <param name="errors">The errors. Errors are sufficient to totally prevent the entity being valid.</param>
    ''' <param name="warnings">The warnings. Entities with warnings alone are still valid, but the user should be notified.</param>
    Public Sub Validate(ByRef errors As String(), ByRef warnings As String())

        ' Get errors and warnings
        Dim ResultingErrors As New List(Of String)
        Dim ResultingWarnings As New List(Of String)
        Validate(ResultingErrors, ResultingWarnings)

        ' Return errors and warnings
        errors = ResultingErrors.ToArray
        warnings = ResultingWarnings.ToArray

    End Sub

    Protected Overridable Sub Validate(ByVal errors As List(Of String), ByVal warnings As List(Of String))

    End Sub

    Public Overridable Sub CalculateComputedFields()

    End Sub

End Class
